/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
#ifndef __HPM6E00_PMP_H
#define __HPM6E00_PMP_H

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus*/
#include "core/include/hpm6e00_regs_csr.h"
#include "common/hpm_errno.h"
#include "riscv/riscv_core.h"
#include <stdio.h>
#include <stdint.h>

/* \brief 起始地址 n 对齐，n 必须的 2 的倍数对齐长度*/
#define PMP_NAPOT_ADDR(x, n) (((uint32_t)(x) >> 2) | (((uint32_t)(n) - 1U) >> 3))
/* \brief PMP 物理内存保护配置*/
#define PMP_CFG(r, w, x, m, l) ((r) | ((w) << 1) | ((x) << 2) | ((m) << 3) | ((l) << 7))

/* \brief 物理内存保护配置定义*/
#define PMP_READ_EN             (1U)
#define PMP_READ_DIS            (0U)
#define PMP_WRITE_EN            (1U)
#define PMP_WRITE_DIS           (0U)
#define PMP_EXECUTE_EN          (1U)
#define PMP_EXECUTE_DIS         (0U)
#define PMP_ADDR_MATCH_MODE_OFF (0U)
#define PMP_ADDR_MATCH_TOR      (1U)
#define PMP_ADDR_MATCH_NAPOT    (3U)
#define PMP_REG_LOCK            (1U)
#define PMP_REG_UNLOCK          (0U)

/* \brief 物理内存属性配置定义*/
#define PMA_MEM_TYPE_DEV_NON_BUF             (0U)
#define PMA_MEM_TYPE_DEV_BUF                 (1U)
#define PMA_MEM_TYPE_MEM_NON_CACHE_NON_BUF   (2U)
#define PMA_MEM_TYPE_MEM_NON_CACHE_BUF       (3U)
#define PMA_MEM_TYPE_MEM_WT_NO_ALLOC         (4U)
#define PMA_MEM_TYPE_MEM_WT_READ_ALLOC       (5U)
#define PMA_MEM_TYPE_MEM_WB_NO_ALLOC         (8U)
#define PMA_MEM_TYPE_MEM_WB_READ_ALLOC       (9U)
#define PMA_MEM_TYPE_MEM_WB_WRITE_ALLOC      (10U)
#define PMA_MEM_TYPE_MEM_WB_READ_WRITE_ALLOC (11U)
#define PMA_MEM_TYPE_EMPTY_HOLE              (15U)

#define PMA_AMO_EN  (0U)
#define PMA_AMO_DIS (1U)

/* \brief 起始地址 n 对齐，n 必须的 2 的倍数对齐长度*/
#define PMA_NAPOT_ADDR(x, n) (((uint32_t)(x) >> 2) | ((((uint32_t)(n) - 1U) >> 3)))
/* \brief PMA 物理内存属性配置*/
#define PMA_CFG(m, t, n) ((m) | ((t) << 2) | ((n) << 6))

/* \brief 物理内存保护结构体*/
typedef struct hpm_pmp_entry {
    union {
        struct {
            uint8_t read_access_ctrl: 1;
            uint8_t write_access_ctrl: 1;
            uint8_t execution_ctrl: 1;
            uint8_t addr_matching_mode: 2;
            uint8_t reserved: 2;
            uint8_t lock: 1;
        };
        uint8_t val;
    } pmp_cfg;
    uint8_t reserved0[3];
    uint32_t pmp_addr;
    union {
        struct {
            uint8_t entry_addr_matching_mode: 2;
            uint8_t mem_type_attribute: 4;
            uint8_t automic_mem_operation_ctrl: 1;
            uint8_t reserved: 1;
        };
        uint8_t val;
    } pma_cfg;
    uint8_t reserved1[3];
    uint32_t pma_addr;
} hpm_pmp_entry_t;

/**
 * \brief 物理内存保护配置
 *
 * \param[in] p_entry        物理内存保护条目结构体
 * \param[in] num_of_entries 条目数量
 *
 * \retval 成功返回 0
 */
int hpm_pmp_cfg(hpm_pmp_entry_t *p_entry, uint32_t num_of_entries);
/**
 * \brief 关闭物理内存保护
 */
void hpm_pmp_disable(void);
#ifdef __cplusplus
}
#endif  /* __cplusplus  */

#endif
